/**
 * 
 */
package judesart.app.client.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import judesart.app.domain.Role;
import judesart.app.domain.User;
import judesart.app.domain.UserRole;

import com.allen_sauer.gwt.log.client.Log;
import com.extjs.gxt.ui.client.data.BaseModel;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelFactory;
import com.extjs.gxt.ui.client.data.BeanModelLookup;
import com.extjs.gxt.ui.client.data.BeanModelMarker;
import com.extjs.gxt.ui.client.data.BeanModelMarker.BEAN;

public class UserModel extends BaseModel
{
    @BEAN(User.class)
    public static interface UserBeanModel extends BeanModelMarker
    {
    }

    @BEAN(UserRole.class)
    public static interface UserRoleBeanModel extends BeanModelMarker
    {
    }

    BeanModel model;
    String passwordAgain;

    public static UserModel createModel(User user)
    {
        return new UserModel(user);
    }

    public static List<UserModel> createModel(List<User> users)
    {
        List<UserModel> result = new ArrayList<UserModel>(users.size());
        for (User user2 : users)
        {
            result.add(createModel(user2));
        }
        return result;
    }

    public User getBean()
    {
        return (User) model.getBean();
    }

    private UserModel(User bean)
    {
        BeanModelFactory factory = BeanModelLookup.get().getFactory(
                bean.getClass());
        model = factory.createModel(bean);
        passwordAgain = bean.getPassword();
    }

    @Override
    public <X> X get(String property)
    {
        X result = null;
        boolean found = false;
        if (property.equals("roles"))
        {
            found = true;
            String rolesValue = new String();
            for (UserRole userRole : getBean().getUserRoles())
            {
                rolesValue += (rolesValue.length() > 0 ? ", " : "")
                        + userRole.getRole().label();
            }
            result = (X) rolesValue;
        }
        if (!found)
        {
            for (Role role : Role.values())
            {
                if (property.equalsIgnoreCase(role.name()))
                {
                    result = (X) getRole(role);
                    found = true;
                    break;
                }
            }
        }
        if (!found)
        {
            if (property.equals("passwordAgain"))
            {
                result = (X) passwordAgain;
            } else
            {
                result = (X) model.get(property);
            }
        }
        Log.debug("get property " + property + " : " + result + "");
        return result;
    }

    private <X> X getRole(Role role)
    {
        for (UserRole userRole : getBean().getUserRoles())
        {
            if (userRole.getRole().equals(role))
            {
                return (X) Boolean.TRUE;
            }
        }
        return (X) Boolean.FALSE;
    }

    @Override
    public Map<String, Object> getProperties()
    {
        Map<String, Object> properties = model.getProperties();
        for (Role role : Role.values())
        {
            properties.put(role.name(), getRole(role));
        }
        return properties;
    }

    @Override
    public Collection<String> getPropertyNames()
    {
        Collection<String> propertyNames = model.getPropertyNames();
        for (Role role : Role.values())
        {
            propertyNames.add(role.name());
        }
        return propertyNames;
    }

    @Override
    public <X> X remove(String property)
    {
        X oldValue = (X) model.remove(property);
        notifyPropertyChanged(property, null, oldValue);
        return oldValue;
    }

    @Override
    public <X> X set(String property, X value)
    {
        Log.debug("set property " + property + " : " + value + "");
        X oldValue = null;
        boolean found = false;
        for (Role role : Role.values())
        {
            if (property.equalsIgnoreCase(role.name()))
            {
                oldValue = setRole(role, value);
                found = true;
                break;
            }
        }
        if (!found)
        {
            if (property.equals("passwordAgain"))
            {
                oldValue = (X) passwordAgain;
                passwordAgain = (String) value;
            } else
            {
                oldValue = model.set(property, value);
            }
        }
        notifyPropertyChanged(property, value, oldValue);
        return oldValue;
    }

    private <X> X setRole(Role role, X newValue)
    {
        X oldValue = (X) getRole(role);
        if (newValue.equals(Boolean.TRUE))
        {
            getBean().addRole(role);
        } else
        {
            getBean().removeRole(role);
        }
        return oldValue;
    }

}